package com.epoint.java8;

import com.epoint.java8.domain.Person;
import com.sun.xml.internal.ws.api.model.wsdl.WSDLOutput;
import org.junit.Test;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 学习Stream
 *
 * 他可以指定你希望对集合进行的操作，可以执行非常复杂的查找、过滤、映射数据等操作。
 * 使用StreamAPI对集合数据进行操作，就类似于你使用sql执行的数据库查询
 *
 * 为什么要使用Stream API
 * 实际开发中，项目中多数数据库都来自于Mysql等，但是现在数据库多了，可能是MongDB、Redis等。而这些NoSQL的数据就需要Java层面去处理了
 *
 *  Steam的操作3个步骤
 *      A.创建Stream：一个数据源，获取一个流
 *      B.中间操作：一个中间操作链，对数据源的数据进行处理
 *      C.终止操作：一旦执行终止操作，就执行中间操作链，并产生结果。之后，不会再被使用
 *
 *
 */
public class StreamAPIDemo {

    /**
     * 中间操作
     *  filter 过滤
     */
    @Test
    public void test1(){

        List<Person> list = generatePerson();

        // 过滤性别为男的数据
        list.stream().filter(e -> e.getSex() == 1).forEach(System.out::println);
    }

    /**
     * 映射 map
     * map可以映射局部的数据，比如
     *
     * 查出来的是List<Student>
     *     但是map之后，我可以转化成List<String>  名称集合
     */
    @Test
    public void test2(){
        List<Person> list = generatePerson();
        list.stream().map(e -> "强化后：" + e.getName()).forEach(System.out::println);
    }

    /**
     * distinct
     *
     * 依赖于对象的equals的方法
     */
    @Test
    public void test3(){
        List<Person> list = generatePerson();
        list.stream().distinct().forEach(System.out::println);
    }

    /**
     * sorted
     *
     *
     */
    @Test
    public void test4(){
        List<Person> list = generatePerson();
        list.stream()
                .sorted( (o1, o2) -> {
                    int i = o2.getAge() - o1.getAge();
                    i = i != 0 ? i : Integer.parseInt(o2.getId()) - Integer.parseInt(o1.getId());
                    return i;
                })
                .forEach(System.out::println);
    }

    /**
     * 终端操作
     */
    @Test
    public void test5(){
//        allMatch(Predicate p)- 检查是否匹配所有元素。练习:是否所有的员工的年龄都大于18
        List<Person> list = generatePerson();
        boolean b = list.stream().allMatch(e -> e.getAge() >= 18);
        System.out.println(b);

//        anyMatch(Predicate p)-检查是 否至少匹配一个元素。 练习:是否存在员工是女生
        boolean b1 = list.stream().anyMatch(e -> e.getAge() == 2);
        System.out.println(b1);

//        noneMatch(Predicate p)-检查是否没有匹配的元素。练习:是否存在员工姓“雷”
        boolean name = list.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(name);

//        findFirst-返回第一个元素
        Optional<Person> first = list.stream().findFirst();
        System.out.println(first);

//        count-返回流中元素的总 个数
        long count = list.stream().count();
        System.out.println(count);

//        max(Comparator c)-返回流中最大值
//        (o1, o2) -> o1.getAge() - o2.getAge()   int compare(T o1, T o2);
        Optional<Integer> max = list.stream().map(Person::getAge).max(Integer::compare);
        System.out.println(max);

//        min(Comparator c)-返回流中最小值
        Optional<Integer> min = list.stream().map(e -> e.getAge()).min(Integer::compare);
        System.out.println(min);

//        forEach(Consumer c)-内部迭代
        list.stream().forEach(System.out :: println);
    }

    /**
     * 终端操作-》collect
     * 我们经常有这么个诉求：把List<User>中 获取List<String>（人员的名称）
     * 把一个大集合里的东西 找到我希望的东西，然后形成一个新的集合
     */
    @Test
    public void test6(){
        List<Person> list = generatePerson();

        // Collectors.toList() java提供的方法，意思是把结果封装成List
        List<String> collect = list.stream().map(Person::getName).collect(Collectors.toList());
        System.out.println(collect);


        // map 很特殊
        Map<String, String> collect1 = list.stream().distinct().collect(Collectors.toMap(Person::getId, Person::getName));
        System.out.println(collect1);

    }

    /**
     * 终端操作-》归约 reduce
     *
     * 将几个元素汇总成一个值
     * 觉得和collect类似，只是 collect返回的还是一个集合，reduce可以直接变成一个数值，用于做 统计汇总 的地方比较好
     */
    @Test
    public void test7(){
        List<Person> list = generatePerson();
        // reduece 参数1：初始值 参数2：定义怎么汇总的一个规则，这里只是把值进行相加
        Integer reduce = list.stream().map(Person::getAge).reduce(6, (e1, e2) -> e1 + e2);
        System.out.println(reduce);
    }

    private List<Person> generatePerson(){
        List<Person> list = new ArrayList<>();
        list.add(new Person("001", "纪宽豪", 28, 1));
        list.add(new Person("001", "纪宽豪", 18, 1));
        list.add(new Person("002", "王欣悦", 24, 2));
        list.add(new Person("003", "王一雄", 24, 1));
        return list;
    }


}
